/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package symulatorwindy.logic;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author głodoś
 */
public class NajblizszeWezwanie implements IAlgorytm{

    private int floorCount;
    private int startFloor;
    private List<Pasazer> pasazerowie;

    public NajblizszeWezwanie(){
        pasazerowie = new ArrayList<Pasazer>();
    }
    public List<Pietro> trasa(List<Pasazer> pasazerowie) {
        this.pasazerowie.addAll(pasazerowie);
        return wyznacz(startFloor);
    }

    public List<List<Pietro>> trasaDwieWindy(List<Pasazer> pasazerowie) {
         this.pasazerowie.addAll(pasazerowie);
        final List<List<Pietro>> trasy = new ArrayList<List<Pietro>>();
        trasy.add(null);trasy.add(null);
        //final List<Pietro> inThread = new ArrayList<Pietro>();
        Thread t = new Thread(){
            public void run(){
                trasy.set(1, wyznacz(floorCount));
            }
        };t.start();
        trasy.set(0, wyznacz(0));
        try {
            t.join();
            return trasy;
        } catch (InterruptedException ex) {
            Logger.getLogger(NajblizszeWezwanie.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

    private List<Pietro> wyznacz(int startFloor){
        List<Pietro> trasa = new ArrayList<Pietro>();
        int floor = startFloor;
        while(!this.pasazerowie.isEmpty()){
            List<Pietro> kierunek = initList();
            Pasazer closest = findClosest(floor);
            kierunek.get(closest.getStart()).pasazerowieWsiadający.add(closest);
            kierunek.get(closest.getStop()).pasazerowieWysiadajacy.add(closest);
            int start = closest.getStart();
            int end = closest.getStop();
            if(start<end){
                //bierzemy tych co na gore
                for(int i = start;i<=end;i++){
                    for(Pasazer p : getPassengersOnFloorUp(i)){
                        kierunek.get(i).pasazerowieWsiadający.add(p);
                        kierunek.get(p.getStop()).pasazerowieWysiadajacy.add(p);
                        if(p.getStop()>end)
                            end = p.getStop();
                    }
                }
            }else{
                //bierzemy tych co w dol
                for(int i = start;i>=end;i--){
                    for(Pasazer p : getPassengersOnFloorDown(i)){
                        kierunek.get(i).pasazerowieWsiadający.add(p);
                        kierunek.get(p.getStop()).pasazerowieWysiadajacy.add(p);
                        if(p.getStop()<end)
                            end = p.getStop();
                    }
                }
                Collections.sort(kierunek, Collections.reverseOrder());
            }
            floor = end;
            trimList(kierunek);
            trasa.addAll(kierunek);
        }
        return trasa;
    }

    private List<Pietro> initList(){
        ArrayList<Pietro> list = new ArrayList<Pietro>();
        for(int i = 0;i<floorCount;i++){
            list.add(new Pietro(i));
        }
        return list;
    }

    private void trimList(List<Pietro> list){
        for(int i = list.size()-1;i>=0;i--){
            Pietro p = list.get(i);
            if(p.pasazerowieWsiadający.isEmpty() && p.pasazerowieWysiadajacy.isEmpty())
                list.remove(i);
        }
    }
    public void setMaxPietro(int maxPietro) {
        this.floorCount = maxPietro;
        startFloor = maxPietro/2;
    }

    private synchronized List<Pasazer> getPassengersOnFloorUp(int floor){
        ArrayList<Pasazer> list = new ArrayList<Pasazer>();
        for(Pasazer p : pasazerowie){
            if(p.naGore() && p.getStart() == floor)
                list.add(p);
        }
        pasazerowie.removeAll(list);
        return list;
    }
    private synchronized List<Pasazer> getPassengersOnFloorDown(int floor){
        ArrayList<Pasazer> list = new ArrayList<Pasazer>();
        for(Pasazer p : pasazerowie){
            if(!p.naGore() && p.getStart() == floor)
                list.add(p);
        }
        pasazerowie.removeAll(list);
        return list;
    }

    private synchronized Pasazer findClosest(int floor){
        Pasazer closest = null;
        int smallest=999999999;
        for(Pasazer p : pasazerowie){
            int roznica = Math.abs(floor-p.getStart());
            if(roznica<smallest){
                closest = p;
                smallest = roznica;
            }
        }
        pasazerowie.remove(closest);
        return closest;
    }


}
